<template>
  <n-form inline :model="database" ref="formRef" :rules="rules">
    <n-form-item label="数据库类型" path="type">
      <n-select
        v-model:value="database.type"
        :options="DB_TYPES"
        label-field="type"
        value-field="type"
        @update:value="dbTypeChange"
        placeholder="数据库类型"
        class="select"
      />
    </n-form-item>
    <n-form-item label="数据库地址" path="address">
      <n-input v-model:value="database.address" placeholder="IP/域名" />
    </n-form-item>
    <n-form-item label="端口" path="port">
      <n-input-number
        v-model:value="database.port"
        :show-button="false"
        :min="1"
        :max="65535"
        placeholder="数据库端口号"
      />
    </n-form-item>
    <n-form-item label="逻辑库" path="schema">
      <n-input v-model:value="database.schema" placeholder="连接的逻辑库" />
    </n-form-item>
    <n-form-item label="账户" path="username">
      <n-input v-model:value="database.username" placeholder="登录用户名" />
    </n-form-item>
    <n-form-item label="密码" path="password">
      <n-input
        v-model:value="database.password"
        placeholder="登录密码"
        type="password"
        show-password-on="mousedown"
      />
    </n-form-item>
    <n-form-item>
      <n-button
        attr-type="button"
        type="primary"
        @click="formHandle"
        :loading="connectLoading"
        v-show="!isConnected"
      >
        连接
      </n-button>
      <n-button
        attr-type="button"
        type="primary"
        @click="close"
        v-show="isConnected"
      >
        取消连接
      </n-button>
    </n-form-item>
  </n-form>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, Ref, inject } from "vue";
import { DataBase } from "@/types/interfaces";
import {
  DB_TYPES,
  DB_CACHE,
  TOKEN_STORAGE,
  DB_CONNECTED_INJECT,
} from "@/types/constant";
import { FormInst, useMessage } from "naive-ui";
import { dbConnect, dbClose } from "@/utils/api";
// 信息提示
const message = useMessage();
// 数据库连接参数
const database = ref<DataBase>({
  type: null,
  address: null,
  port: null,
  schema: null,
  username: null,
  password: null,
});
// 连接Loading
const connectLoading = ref(false);
// 记录连接状态
const isConnected = inject(DB_CONNECTED_INJECT) as Ref<boolean>;
// 表单验证
const formRef = ref<FormInst | null>(null);
const rules = {
  type: { required: true, message: "请选择数据库类型", trigger: "blur" },
  address: { required: true, message: "请输入连接地址", trigger: "blur" },
  // TODO 这个验证有BUG
  // port: [
  //   { required: true, message: "请输入连接端口", trigger: "blur" },
  // ],
  schema: { required: true, message: "请输入连接的逻辑库", trigger: "blur" },
  username: { required: true, message: "请输入登录用户名", trigger: "blur" },
  password: { required: true, message: "请输入登录密码", trigger: "blur" },
};

// 初始化加载上次的数据源配置
onMounted(() => {
  loadDBCache();
  // window.addEventListener('beforeunload', beforeunloadHandler);
});
// 组件销毁时，释放资源
onBeforeUnmount(() => {
  close();
  // window.removeEventListener('beforeunload', beforeunloadHandler);
});

// 数据库类型变更监听：赋值默认端口号
const dbTypeChange = (option: string) => {
  for (const item of DB_TYPES) {
    if (item.type === option) {
      database.value.port = item.port;
      return;
    }
  }
};
// 表单提交，点击连接，表单校验
const formHandle = (e: MouseEvent) => {
  e.preventDefault();
  formRef.value
    ?.validate()
    .then(() => connect())
    .catch((_e) => {});
};
// 请求API：连接数据库
const connect = async () => {
  connectLoading.value = true;
  const res = await dbConnect(database.value);
  if (res.code !== 200) {
    message.error(res.message || "连接失败");
    connectLoading.value = false;
    return;
  }
  message.success("连接成功");
  connectLoading.value = false;
  isConnected.value = true;
  localStorage.setItem(TOKEN_STORAGE, res.data?.token || "");
  setDBCache();
};
// 连接配置缓存
const setDBCache = () => {
  localStorage.setItem(
    DB_CACHE,
    JSON.stringify({
      ...database.value,
      password: null,
    })
  );
};
// 加载连接配置缓存
const loadDBCache = () => {
  const cache = localStorage.getItem(DB_CACHE);
  if (cache) {
    const config = JSON.parse(cache);
    database.value = config;
  }
};
// 断开数据库连接
const close = async () => {
  if (isConnected.value) {
    const res = await dbClose();
    if (res.code === 200) {
      localStorage.removeItem(TOKEN_STORAGE);
      isConnected.value = false;
      message.success("已取消连接");
      return;
    }
    message.error(res.message || "取消连接失败");
  }
};
// TODO 测试无效 离开网页时关闭资源
// const beforeunloadHandler = async (event: BeforeUnloadEvent) => {
//   event.preventDefault();
//   await close();
// }
</script>

<style scoped>
.select {
  width: 11.25rem;
}
</style>
